﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

// Reviewed

#pragma once

#include "GcmpModelInterface.h"
#include "Vector2d.h"
#include "Color.h"
#include "GcmpApiDeclaration.h"

namespace gcmp
{
    /// \brief 图形材质数据
    class GCMP_MODEL_INTERFACE_EXPORT IGraphicsMaterialData
    {
    public:

        /// \brief 通过 alpha 测试后的显示效果
        enum class AlphaTestEffect : std::uint8_t
        {
            HollowOut = 0,        /// < 镂空
            UseDiffuseColor = 1   /// < 使用材质的漫反射光颜色
        };
        /*!
        * @enum WrapMode
        * @brief 定义纹理环绕的模式
        */
        enum class EnWrapMode : int32_t
        {
            //! 截取
            CLAMP = 1,
            //! 重复
            REPEAT = 2,
            //! 镜像
            MIRROR = 3,
            //! 纹理坐标取值超过[0.0, 1.0]范围的，设置为边框颜色
            BORDER = 4
        };

        /// \brief 析构函数
        virtual ~IGraphicsMaterialData() {}

#pragma region static methods
        /// \brief 创建图形材质数据
        /// \return 返回创建的图形材质数据
        static OwnerPtr<IGraphicsMaterialData> Create();
#pragma endregion static methods

        /// \brief 设置环境光
        /// \param color 目标颜色
        /// \return 被修改的图形材质数据自身
        virtual IGraphicsMaterialData& SetAmbient(const Color& color) = 0;

        /// \brief 获取环境光
        /// \return 返回环境光
        virtual Color GetAmbient() const = 0;

        /// \brief 设置漫反射光
        /// \param color 目标颜色
        /// \return 被修改的图形材质数据自身
        virtual IGraphicsMaterialData& SetDiffuse(const Color& color) = 0;

        /// \brief 获取漫反射光
        /// \return 返回漫反射光
        virtual Color GetDiffuse() const = 0;

        /// \brief 设置镜面高光
        /// \param color 目标颜色
        /// \return 被修改的图形材质数据自身
        virtual IGraphicsMaterialData& SetSpecular(const Color& color) = 0;

        /// \brief 获取镜面高光
        /// \return 返回镜面高光
        virtual Color GetSpecular() const = 0;

        /// \brief 设置透明度
        /// \param transparency 目标透明度
        /// \return 被修改的图形材质数据自身
        virtual IGraphicsMaterialData& SetTransparency(double transparency) = 0;

        /// \brief 获取透明度
        /// \return 返回透明度
        virtual double GetTransparency() const = 0;

        /// \brief 设置镜面指数
        /// \param shininess 目标镜面指数
        /// \return 被修改的图形材质数据自身
        virtual IGraphicsMaterialData& SetShininess(double shininess) = 0;

        /// \brief 获取镜面指数
        /// \return 返回镜面指数
        virtual double GetShininess() const = 0;

#pragma region DiffuseTexture
        /// \brief 设置是否启用漫反射贴图
        /// \param enableOrNot 是否启用
        /// \return 被修改的图形材质数据自身
        virtual IGraphicsMaterialData& EnableDiffuseTexture(bool enableOrNot) = 0;

        /// \brief 是否启用漫反射贴图
        /// \return 返回是否启用漫反射贴图
        virtual bool IsDiffuseTextureEnabled() const = 0;
        
        /// \brief 设置漫反射贴图文件路径
        /// 
        /// 目标路径可以是贴图文件的绝对路径，如果是相对路径，则会依次在如下路径查找
        /// 1. 材质实例所在的路径
        /// 2. 材质库内置材质路径
        /// \param filePath 目标路径
        /// \return 被修改的图形材质数据自身
        virtual IGraphicsMaterialData& SetDiffuseTextueFilePath(const std::wstring& filePath) = 0;

        /// \brief 获取漫反射贴图文件路径
        /// 
        /// 如果图形材质数据是从材质实例获取的，那么获取的路径是绝对路径
        /// \return 返回漫反射贴图文件路径
        virtual std::wstring GetDiffuseTextueFilePath() const = 0;
       
        /// \brief 设置漫反射贴图偏移量
        /// \param offset 目标偏移量
        /// \return 被修改的图形材质数据自身
        virtual IGraphicsMaterialData& SetDiffuseTexureOffset(const Vector2d& offset) = 0;

        /// \brief 获取漫反射贴图偏移量
        /// \return 返回漫反射贴图偏移量
        virtual Vector2d GetDiffuseTexureOffset() const = 0;
        
        /// \brief 设置漫反射贴图旋转量
        /// \param rotation 目标旋转量（单位：角度）
        /// \return 被修改的图形材质数据自身
        virtual IGraphicsMaterialData& SetDiffuseTexureRotation(double rotation) = 0;

        /// \brief 获取漫反射贴图旋转量
        /// \return 返回漫反射贴图旋转量（单位：角度）
        virtual double GetDiffuseTexureRotation() const = 0;
        
        /// \brief 设置漫反射贴图缩放量
        /// \param scale 目标缩放量
        /// \return 被修改的图形材质数据自身
        virtual IGraphicsMaterialData& SetDiffuseTexureScale(const Vector2d& scale) = 0;

        /// \brief 获取漫反射贴图缩放量
        /// \return 返回漫反射贴图缩放量
        virtual Vector2d GetDiffuseTexureScale() const = 0;

        /// \brief 设置漫反射贴图环绕模式
        /// \param wrapMode 环绕模式
        /// \return 自己（this）
        virtual IGraphicsMaterialData& SetDiffuseWrapMode(EnWrapMode wrapMode) = 0;

        /// \brief 获取漫反射贴图环绕模式
        /// \return 环绕模式
        virtual EnWrapMode GetDiffuseWrapMode() const = 0;

#pragma endregion DiffuseTexture

#pragma region BackDiffuseTexture

        /// \brief 设置是否使用双面材质
        /// \param useDoubleSideMaterial 是否使用双面材质
        /// \return 被修改的图形材质数据自身
        virtual void SetUseDoubleSideMaterial(bool useDoubleSideMaterial) = 0;

        /// \brief 获取是否使用双面材质
        /// \return 返回是否使用双面材质
        virtual bool GetUseDoubleSideMaterial() const = 0;

        /// \brief 设置是否启用背面漫反射贴图
        /// \param enableOrNot 是否启用
        /// \return 被修改的图形材质数据自身
        virtual IGraphicsMaterialData& EnableBackDiffuseTexture(bool enableOrNot) = 0;

        /// \brief 是否启用背面漫反射贴图
        /// \return 返回是否启用背面漫反射贴图
        virtual bool IsBackDiffuseTextureEnabled() const = 0;

        /// \brief 设置背面漫反射贴图文件路径
        /// 
        /// 目标路径可以是贴图文件的绝对路径，如果是相对路径，则会依次在如下路径查找
        /// 1. 材质实例所在的路径
        /// 2. 材质库内置材质路径
        /// \param filePath 目标路径
        /// \return 被修改的图形材质数据自身
        virtual IGraphicsMaterialData& SetBackDiffuseTextueFilePath(const std::wstring& filePath) = 0;

        /// \brief 获背面取漫反射贴图文件路径
        /// 
        /// 如果图形材质数据是从材质实例获取的，那么获取的路径是绝对路径
        /// \return 返回背面漫反射贴图文件路径
        virtual std::wstring GetBackDiffuseTextueFilePath() const = 0;

        /// \brief 设置背面漫反射贴图偏移量
        /// \param offset 目标偏移量
        /// \return 被修改的图形材质数据自身
        virtual IGraphicsMaterialData& SetBackDiffuseTexureOffset(const Vector2d& offset) = 0;

        /// \brief 获取背面漫反射贴图偏移量
        /// \return 返回背面漫反射贴图偏移量
        virtual Vector2d GetBackDiffuseTexureOffset() const = 0;

        /// \brief 设置背面漫反射贴图旋转量
        /// \param rotation 目标旋转量（单位：角度）
        /// \return 被修改的图形材质数据自身
        virtual IGraphicsMaterialData& SetBackDiffuseTexureRotation(double rotation) = 0;

        /// \brief 获取背面漫反射贴图旋转量
        /// \return 返回漫反射贴图旋转量（单位：角度）
        virtual double GetBackDiffuseTexureRotation() const = 0;

        /// \brief 设置背面漫反射贴图缩放量
        /// \param scale 目标缩放量
        /// \return 被修改的图形材质数据自身
        virtual IGraphicsMaterialData& SetBackDiffuseTexureScale(const Vector2d& scale) = 0;

        /// \brief 获取背面漫反射贴图缩放量
        /// \return 返回背面漫反射贴图缩放量
        virtual Vector2d GetBackDiffuseTexureScale() const = 0;

#pragma endregion BackDiffuseTexture
        
        /// \brief 设置是否启用法线贴图
        ///
        /// 注：法线纹理特性在平面视图（除三维视图外的所有视图）中不起作用，因为平面视图关闭了光照2020/6/1。（详细参考GgpCanvas::InitOptions()函数）
        /// \param enableOrNot 是否启用
        /// \return 被修改的图形材质数据自身
        virtual IGraphicsMaterialData& EnableNormalTexture(bool enableOrNot) = 0;

        /// \brief 是否启用法线贴图
        /// \return 返回是否启用法线贴图
        virtual bool IsNormalTextureEnabled() const = 0;

        /// 目标路径可以是贴图文件的绝对路径，如果是相对路径，则会依次在如下路径查找
        ///
        /// 1. 材质实例所在的路径
        /// 2. 材质库内置材质路径
        /// \param filePath 目标路径
        /// \return 被修改的图形材质数据自身
        virtual IGraphicsMaterialData& SetNormalTextueFilePath(const std::wstring& filePath) = 0;
        
        /// \brief 获取法线贴图文件路径
        /// 
        /// 如果图形材质数据是从材质实例获取的，那么获取的路径是绝对路径
        /// \return 返回漫反射贴图文件路径
        virtual std::wstring GetNormalTextueFilePath() const = 0;
        
        /// \brief 设置是否开启Alpha测试
        /// \param enableOrNot 是否启用
        /// \return 被修改的图形材质数据自身
        virtual IGraphicsMaterialData& EnableAlphaTest(bool enableOrNot) = 0;

        /// \brief 是否启用Alpha测试
        /// \return 返回是否启用Alpha测试
        virtual bool IsAlphaTestEnabled() const = 0;

        /// \brief 设置镂空阈值
        /// \param alphaTestThreshold 镂空阈值
        virtual IGraphicsMaterialData& SetAlphaTestThreshold(double alphaTestThreshold) = 0;
    
        /// \brief 获取镂空阈值
        /// \return 返回镂空阈值
        virtual double GetAlphaTestThreshold() const = 0;

        /// \brief 设置Alpha测试通过后的显示效果，是镂空或者显示材质的漫反射光颜色
        /// \param effectType 显示效果类型
        virtual IGraphicsMaterialData& SetAlphaTestEffect(AlphaTestEffect effectType) = 0;

        /// \brief 获取Alpha测试通过后的显示效果，是镂空或者显示材质的漫反射光颜色
        /// \return 显示效果类型
        virtual AlphaTestEffect GetAlphaTestEffect() const = 0;

        /// \brief 重载==符，判断两个图形材质数据是否相同
        /// \param another 需要对比的目标图形材质数据
        /// \return true-相同，false-不同
        virtual bool operator==(const IGraphicsMaterialData& another) const = 0;

        /// \brief 重载!=符，判断两个图形材质数据是否不同
        /// \param another 需要对比的目标图形材质数据
        /// \return true-不同，false-相同
        virtual bool operator!=(const IGraphicsMaterialData& another) const = 0;

        /// \brief 重载<运算符
        /// \param another 用于比较的对象
        /// \return 如果小于比较的对象，返回true，否则返回false
        virtual bool operator<(const IGraphicsMaterialData& another) const = 0;
        
        /// \brief 克隆
        ///
        /// 将自己复制一份
        /// \return 自己的副本
        virtual OwnerPtr<IGraphicsMaterialData> Clone() const = 0;

        /// \brief 将图形材质数据的各字段重置为默认值
        /// \param ambient 环境光颜色
        /// \param diffuse 漫反射颜色
        /// \param specular 镜面高光颜色
        /// \param transparency 透明度
        /// \param shininess 镜面指数
        /// \param isDiffuseTextureEnabled 是否启用漫反射贴图
        /// \param diffuseTexureFilePath 漫反射贴图文件路径
        /// \param diffuseTexureOffset 漫反射贴图偏移
        /// \param diffuseTexureRotation 漫反射贴图旋转
        /// \param diffuseTexureScale 漫反射贴图缩放
        /// \param isBackDiffuseTextureEnabled 背面是否启用漫反射贴图
        /// \param backDiffuseTexureFilePath 背面漫反射贴图文件路径
        /// \param backDiffuseTexureOffset 背面漫反射贴图偏移
        /// \param backDiffuseTexureRotation 背面漫反射贴图旋转
        /// \param backDiffuseTexureScale 背面漫反射贴图缩放
        /// \param isNormalTextureEnabled 是否启用法线贴图
        /// \param normalTexureFilePath 法线贴图文件路径
        /// \param isAlphaTestEnabled 是否打开alpha测试（启用镂空效果）
        /// \param alphaTestThreshold 镂空阈值
        /// \param alphaTestEffect 通过alpha测试后的显示效果
        /// \return 被重置的图形样式数据自身
        IGraphicsMaterialData& Reset(
            const Color& ambient = Color::GainSboro,
            const Color& diffuse = Color::GainSboro,
            const Color& specular = Color::Black,
            double transparency = 1.0,
            double shininess = 0.0,
            bool isDiffuseTextureEnabled = false,
            const std::wstring& diffuseTexureFilePath = L"",
            const Vector2d& diffuseTexureOffset = Vector2d(0.0, 0.0),
            double diffuseTexureRotation = 0.0,
            const Vector2d& diffuseTexureScale = Vector2d(1.0, 1.0),
            bool isNormalTextureEnabled = false,
            const std::wstring& normalTexureFilePath = L"",
            bool isAlphaTestEnabled = true,
            double alphaTestThreshold = 0.01,
            bool useDoubleSideMaterial = false,
            bool isBackDiffuseTextureEnabled = false,
            const std::wstring& backDiffuseTexureFilePath = L"",
            const Vector2d& backDiffuseTexureOffset = Vector2d(0.0, 0.0),
            double backDiffuseTexureRotation = 0.0,
            const Vector2d& backDiffuseTexureScale = Vector2d(1.0, 1.0),
            AlphaTestEffect alphaTestEffect = AlphaTestEffect::HollowOut,
            EnWrapMode diffuseWrapMode = EnWrapMode::REPEAT);
   };

}

